#ifndef __ZENGL_SHADER__
#define __ZENGL_SHADER__

#include <string>

#include "api.hpp"
#include "allocator.hpp"

namespace zen {

	namespace gl {

		/**
		* Returns the shader type, results can be one of: GL_VERTEX_SHADER, GL_FRAGMENT_SHADER or GL_GEOMETRY_SHADER.
		*/
		inline GLint zglGetShaderType(GLuint shader);

		/**
		* Retrieves the shader information log length including null termination character or 0 if there is none.
		*/
		inline GLint zglGetShaderInfoLogLength(GLuint shader);

		/**
		* Retrieves the shader information log as a null terminated string or null if there is none.
		*/
		inline GLchar* zglGetShaderInfoLog(GLuint shader);

		/**
		* Retrieves the shader source length including null termination character or 0 if there is none.
		*/
		inline GLint zglGetShaderSourceLength(GLuint shader);

		/**
		* Retrieves the shader source as a null terminated string or null if there is none.
		*/
		inline GLchar* zglGetShaderSource(GLuint shader);

		/**
		* Returns true if the last compile operation on the shader was successful.
		*/
		inline bool zglGetShaderCompileStatus(GLuint shader);

		/**
		* Returns true if shader is currently flagged for deletion.
		*/
		inline bool zglGetShaderDeleteStatus(GLuint shader);

		/**
		* Registers a shader source directory which will be used by zglShaderSource.
		*/
		void zglRegisterShaderSourceDirectory(const std::string &directory);

		/**
		* Registers a shader source directory which will be used by zglShaderSource.
		*/
		void zglRegisterShaderSourceDirectory(const GLchar* directory);

		/**
		* Replaces the source code in a shader object, same as the original glShaderSource except this one loads
		* the data from file, and preprocess include directives if the preprocess parameter is set to true.
		* The methods preprocessor does not keep in mind the surrounding if/endif preprocessor directives
		* and does not check for infinite recursive inclusion.
		*/
		void zglShaderSource(GLuint shader, const std::string &fileName, bool preprocess = false);

		/**
		* Replaces the source code in a shader object, same as the original glShaderSource except this one loads
		* the data from file, and preprocess include directives if the preprocess parameter is set to true.
		* The methods preprocessor does not keep in mind the surrounding if/endif preprocessor directives
		* and does not check for infinite recursive inclusion.
		*/
		void zglShaderSource(GLuint shader, const GLchar* fileName, bool preprocess = false);


		/**
		* Inline implementations
		*/
		inline GLint zglGetShaderType(GLuint shader) {
			GLint tmp;
			glGetShaderiv(shader, GL_SHADER_TYPE, &tmp);
			return tmp;
		}

		inline GLint zglGetShaderInfoLogLength(GLuint shader) {
			GLint tmp;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &tmp);
			return tmp;
		}

		inline GLchar* zglGetShaderInfoLog(GLuint shader) {
			GLsizei length = zglGetShaderInfoLogLength(shader);
			if (length > 0) {
				GLchar* infoLog = (GLchar*)zglAllocate(length);
				if (infoLog != nullptr) {
					glGetShaderInfoLog(shader, length, &length, infoLog);
					return infoLog;
				}
			}
			return nullptr;
		}

		inline GLint zglGetShaderSourceLength(GLuint shader) {
			GLint tmp;
			glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &tmp);
			return tmp;
		}

		inline GLchar* zglGetShaderSource(GLuint shader) {
			GLsizei length = zglGetShaderSourceLength(shader);
			if (length > 0) {
				GLchar* source = (GLchar*)zglAllocate(length);
				if (source != nullptr) {
					glGetShaderSource(shader, length, &length, source);
					return source;
				}
			}
			return nullptr;
		}

		inline bool zglGetShaderCompileStatus(GLuint shader) {
			GLint tmp;
			glGetShaderiv(shader, GL_COMPILE_STATUS, &tmp);
			return tmp == GL_TRUE;
		}

		inline bool zglGetShaderDeleteStatus(GLuint shader) {
			GLint tmp;
			glGetShaderiv(shader, GL_DELETE_STATUS, &tmp);
			return tmp == GL_TRUE;
		}

	} // namespace gl

} // namespace zen

#endif // __ZENGL_SHADER__
